import json
import requests
from dashscope import Generation

# 1. 定义周边商户查询函数的schema
nearby_places_schema = {
    "name": "search_nearby_places", # name 指定函数名称
    "description": "搜索指定位置周边的商户信息，支持直接输入地址名称或经纬度坐标",
     # parameters 定义函数的入参格式
    "parameters": { 
        "type": "object",
        "properties": {
            "location": {
                "type": "string",
                "description": "位置坐标（经度,纬度）或地址名称，如'116.481028,39.989643'或'北京市朝阳区阜通东大街6号'，地址名称将自动转换为经纬度坐标"
            },
            "keywords": {
                "type": "string",
                "description": "搜索关键字，如餐厅、商场、医院等"
            },
            "radius": {
                "type": "string",
                "description": "查询半径，单位：米，默认3000米，最大50000米"
            },
            "types": {
                "type": "string",
                "description": "POI类型，可选值：餐饮服务、商务住宅、生活服务等，与keywords二者必须至少传入一个"
            },
            "sort_rule": {
                "type": "string",
                "description": "排序规则，可选值：distance（距离优先）、weight（权重优先，默认）"
            }
        },
        "required": ["location"]
    },
    # returns 定义函数的返回格式
    "returns": {
        "type": "object",
        "properties": {
            "total": {
                "type": "string",
                "description": "返回的POI数目"
            },
            "places": {
                "type": "array",
                "description": "周边商户列表",
                "items": {
                    "type": "object",
                    "properties": {
                        "name": {
                            "type": "string",
                            "description": "商户名称"
                        },
                        "address": {
                            "type": "string",
                            "description": "商户地址"
                        },
                        "distance": {
                            "type": "string",
                            "description": "距离中心点的距离，单位：米"
                        },
                        "type": {
                            "type": "string",
                            "description": "商户类型"
                        },
                        "tel": {
                            "type": "string",
                            "description": "联系电话"
                        }
                    }
                }
            }
        }
    }
}

# 2. 实现地理编码函数
def geocode_address(address):
    """将地址名称转换为经纬度坐标，调用高德地图地理编码API"""
    # 高德地图API配置
    api_key = "6e5cc475a52de09c94989f1010ef703a"  # 请替换为你在高德开放平台申请的API密钥
    api_url_base = "https://restapi.amap.com/v3/geocode/geo"
    
    # 构建请求参数
    params = {
        "key": api_key,  # 必填
        "address": address  # 地址 必填
    }
    
    try:
        # 发送API请求
        print("请求高德地图地理编码入参值", params)
        response = requests.get(api_url_base, params=params)
        response.raise_for_status()  # 检查请求是否成功
        print("请求高德地图地理编码返回值", response.text)
        
        # 解析返回的JSON数据
        data = response.json()
        
        # 检查API返回状态码
        if data.get("status") == "1" and data.get("geocodes") and len(data.get("geocodes")) > 0:
            # 提取第一个地理编码结果的坐标
            location = data.get("geocodes")[0].get("location")
            return location
        else:
            print(f"地理编码API返回错误，状态码: {data.get('info')}")
            return None
            
    except requests.exceptions.RequestException as e:
        print(f"请求高德地图地理编码API出错: {str(e)}")
        return None
    except Exception as e:
        print(f"处理地理编码数据出错: {str(e)}")
        return None

# 3. 实现周边商户查询函数
def search_nearby_places(location, keywords="", radius="3000", types="", sort_rule="weight"):
    """搜索指定位置周边的商户信息，调用高德地图周边搜索API"""
    # 高德地图API配置
    api_key = "6e5cc475a52de09c94989f1010ef703a"  # 请替换为你在高德开放平台申请的API密钥
    api_url_base = "https://restapi.amap.com/v3/place/around"

    # 构建请求参数
    params = {
        "key": api_key, # 必填
        "location": location,  # 中心点坐标或地址 必填
        "keywords": keywords # 搜索关键字 可选
        # "radius": radius,      # 查询半径
        # "types": types,        # POI类型
        # "sortrule": sort_rule, # 排序规则
        # "offset": "10"         # 每页记录数，最大25条
    }

    try:
        # 发送API请求
        print("请求高德地图入参值",params)
        response = requests.get(api_url_base, params=params)
        response.raise_for_status()  # 检查请求是否成功
        print("请求高德地图返回值",response.text)
        # 解析返回的JSON数据
        data = response.json()
        # 检查API返回状态码
        if data.get("status") == "1":
            # 提取POI数据
            pois = data.get("pois", [])
            total = data.get("count", "0")
            
            # 构建返回结果，格式与schema一致
            places = []
            for poi in pois:
                place = {
                    "name": poi.get("name", "未知"),
                    "address": poi.get("address", "未知"),
                    "distance": poi.get("distance", "未知"),
                    "type": poi.get("type", "未知"),
                    "tel": poi.get("tel", "未知")
                }
                places.append(place)
                
            result = {
                "total": total,
                "places": places
            }
            return result

        else:
            print(f"API返回错误，状态码: {data.get('info')}")
            return {"total": "0", "places": []}
            
    except requests.exceptions.RequestException as e:
        print(f"请求高德地图API出错: {str(e)}")
        return {"total": "0", "places": []}
    except Exception as e:
        print(f"处理商户数据出错: {str(e)}")
        return {"total": "0", "places": []}

# 3. 定义函数工具列表
function_tools = [
    {
        "type": "function",
        "function": nearby_places_schema # 函数工具的schema
    }
]

# 4. 函数调用处理器
def function_call_handler(function_call):
    """处理模型返回的函数调用请求"""
    arguments = json.loads(function_call.get('arguments', '{}'))
    
    location = arguments.get('location')
    keywords = arguments.get('keywords', '')
    radius = arguments.get('radius', '3000')
    types = arguments.get('types', '')
    sort_rule = arguments.get('sort_rule', 'weight')
    
    # 检查location是否为经纬度格式（包含逗号且可以分割为两个数字）
    is_coordinates = False
    if location and ',' in location:
        try:
            lng, lat = location.split(',')
            float(lng), float(lat)  # 尝试转换为浮点数
            is_coordinates = True
        except (ValueError, TypeError):
            is_coordinates = False
    
    # 如果不是经纬度格式，则调用地理编码API转换为经纬度
    if not is_coordinates:
        print(f"输入的位置'{location}'不是经纬度格式，尝试进行地理编码...")
        geocoded_location = geocode_address(location)
        if geocoded_location:
            print(f"地理编码成功，转换为经纬度坐标: {geocoded_location}")
            location = geocoded_location
        else:
            print(f"地理编码失败，无法获取'{location}'的经纬度坐标")
            return {"total": "0", "places": [], "error": f"无法获取'{location}'的经纬度坐标"}
    
    return search_nearby_places(location, keywords, radius, types, sort_rule)
    

# 调用Qwen模型并处理函数调用
def chat_with_function_calling(api_key, messages, tools=None):
    """使用DashScope SDK调用Qwen模型的函数调用功能"""
    try:
        # 第一次调用模型，可能会返回函数调用请求
        response = Generation.call(
            model='qwen-max',  # 或其他支持函数调用的Qwen模型
            api_key=api_key,
            messages=messages,
            tools=tools,  # 传入可调用的模型
            tool_choice="auto",  # 让模型自动决定是否调用函数
            result_format='message'  # 返回消息格式
        )
        
        # 检查是否有函数调用
        if response.output and response.output.choices:
            message = response.output.choices[0].message
            print("函数调用详情：", message)
            # 如果有函数调用
            if message.get('tool_calls'):
                tool_call = message['tool_calls'][0]
                function_call = tool_call.get('function')
                # 处理函数调用
                function_result = function_call_handler(function_call)
                # 将函数调用结果添加到消息历史
                messages.append({
                    "role": "assistant",
                    "content": None,
                    "tool_calls": [{
                        "id": tool_call.get('id'),
                        "type": "function",
                        "function": function_call
                    }]
                })
                
                # 添加函数执行结果
                messages.append({
                    "role": "tool",
                    "tool_call_id": tool_call.get('id'),
                    "content": json.dumps(function_result, ensure_ascii=False)
                })
                
                # 再次调用模型，获取最终回复
                final_response = Generation.call(
                    model='qwen-max',
                    api_key=api_key,
                    messages=messages,
                    result_format='message'
                )
                
                if final_response.output and final_response.output.choices:
                    return final_response.output.choices[0].message.get('content')
                else:
                    return "模型未返回有效回复"
            else:
                # 没有函数调用，直接返回模型回复
                return message.get('content')
        else:
            return "模型未返回有效回复"
    except Exception as e:
        return f"调用出错: {str(e)}"

# 主函数
def main():
    # 请替换为你的DashScope API密钥
    api_key = "sk-***"
    # 用户消息 - 直接使用地址名称而非经纬度
    messages = [
        {"role": "user", "content": "西安市大华产业园附近有哪些餐厅？"}
    ]
    print("\n测试1: 使用地址名称查询周边餐厅")
    # 调用模型并处理函数调用
    response = chat_with_function_calling(api_key, messages, tools=function_tools)
    print("模型最终回复:")
    print(response)
    
    # 测试2: 使用经纬度坐标查询
    # messages2 = [
    #     {"role": "user", "content": "116.481028,39.989643附近有哪些商场？"}
    # ]
    # print("\n测试2: 使用经纬度坐标查询周边商场")
    # response2 = chat_with_function_calling(api_key, messages2, tools=function_tools)
    # print("模型最终回复:")
    # print(response2)

# 运行示例
if __name__ == "__main__":
    main()